package cz.muni.fi.pv168.reminder.managers.implementation;

import cz.muni.fi.pv168.reminder.DBUtils;
import cz.muni.fi.pv168.reminder.IllegalEntityException;
import cz.muni.fi.pv168.reminder.ServiceFailureException;
import cz.muni.fi.pv168.reminder.managers.AssignmentManager;
import cz.muni.fi.pv168.reminder.entities.Worker;
import cz.muni.fi.pv168.reminder.entities.Task;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.DataSource;

/**
 *
 * @author Katarina Dusickova
 */
public class AssignmentManagerImpl implements AssignmentManager {

    private DataSource ds;
    public static final Logger logger =
            Logger.getLogger(AssignmentManagerImpl.class.getName());

    public void setDataSource(DataSource ds) {
        this.ds = ds;
    }

    private void checkDataSource() {
        if (ds == null) {
            throw new IllegalStateException("DataSource is not set");
        }
    }

    @Override
    public void assignTaskToWorker(Task task, Worker worker) throws ServiceFailureException, IllegalEntityException {
        checkDataSource();
        if (worker == null) {
            throw new IllegalArgumentException("worker is null");
        }
        if (worker.getId() == null) {
            throw new IllegalEntityException("worker id is null");
        }
        if (task == null) {
            throw new IllegalArgumentException("task is null");
        }
        if (task.getId() == null) {
            throw new IllegalEntityException("task id is null");
        }

        Connection conn = null;
        PreparedStatement st = null;
        try {
            conn = ds.getConnection();
            conn.setAutoCommit(false);

            st = conn.prepareStatement("INSERT INTO ASSIGNMENT (taskID,workerID) VALUES (?,?)",
                    Statement.RETURN_GENERATED_KEYS);
            st.setLong(1, task.getId());
            st.setLong(2, worker.getId());

            int count = st.executeUpdate();
            DBUtils.checkUpdatesCount(count, worker, true);



            conn.commit();
            logger.log(Level.SEVERE, "Task added", worker);
        } catch (SQLException ex) {
            String msg = "Error when inserting person into db";
            logger.log(Level.SEVERE, null, ex);
            throw new ServiceFailureException(msg, ex);
        } finally {
            DBUtils.doRollbackQuietly(conn);
            DBUtils.closeQuietly(conn, st);
        }

    }

    @Override
    public void removeTaskFromWorker(Task task, Worker worker) {
        checkDataSource();
        if (task == null) {
            throw new IllegalArgumentException("task is null");
        }
        if (task.getId() == null) {
            throw new IllegalEntityException("task id is null");
        }
        if (task == null) {
            throw new IllegalArgumentException("worker is null");
        }
        if (task.getId() == null) {
            throw new IllegalEntityException("worker id is null");
        }
        Connection conn = null;
        PreparedStatement st = null;
        try {
            conn = ds.getConnection();
            // Temporary turn autocommit mode off. It is turned back on in 
            // method DBUtils.closeQuietly(...) 
            conn.setAutoCommit(false);
            st = conn.prepareStatement("DELETE FROM assignment WHERE taskID = ? AND workerID = ?");
            st.setLong(1, task.getId());
            st.setLong(2, worker.getId());

            int count = st.executeUpdate();
            DBUtils.checkUpdatesCount(count, task, false);
            conn.commit();
        } catch (SQLException ex) {
            String msg = "Error when deleting task from worker";
            logger.log(Level.SEVERE, msg, ex);
            throw new ServiceFailureException(msg, ex);
        } finally {
            DBUtils.doRollbackQuietly(conn);
            DBUtils.closeQuietly(conn, st);
        }
    }

    @Override
    public List<Task> findTasksOfWorker(Worker worker) {
        
        checkDataSource();
        Connection conn = null;
        PreparedStatement st = null;
        TaskManagerImpl taskManager = new TaskManagerImpl();
        taskManager.setDataSource(ds);
        try {
            
            conn = ds.getConnection();
            
            
              st = conn.prepareStatement(
                    "SELECT taskID FROM assignment WHERE workerID = ?");
            
            st.setLong(1, worker.getId());
            
             
            ResultSet rs = st.executeQuery();
             
            List<Task> result = new ArrayList<>();
            
            while (rs.next()) {
                result.add(taskManager.findTaskById(rs.getLong("taskID")));

            }
           
            return result;

        } catch (SQLException ex) {
            throw new ServiceFailureException("Error when retrieving all tasks of worker", ex);
        } finally {
            DBUtils.closeQuietly(conn, st);
        }
    }

    @Override
    public List<Worker> findWorkersOfTask(Task task) {
        checkDataSource();
        Connection conn = null;
        PreparedStatement st = null;
        WorkerManagerImpl workerManager = new WorkerManagerImpl();
        workerManager.setDataSource(ds);
        try {
            conn = ds.getConnection();
            st = conn.prepareStatement(
                    "SELECT workerID FROM assignment WHERE TASKID = ?");
            st.setLong(1, task.getId());
            ResultSet rs = st.executeQuery();

            List<Worker> result = new ArrayList<>();
            
            
            while (rs.next()) {
                result.add(workerManager.findPersonById(rs.getLong("workerID")));
            }
            return result;

        } catch (SQLException ex) {
            throw new ServiceFailureException("Error when retrieving all tasks of worker", ex);
        } finally {
            DBUtils.closeQuietly(conn, st);
        }
    }
}
